/*    
    OpenMheg - A free MHEG-5 library
    Copyright (C) 2008 Dharmesh Malam

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Text;
using Core.Model.Events;
using Core.Model.Data.Generics;
using Core.Model.Data.Variables;
using Core.Model.Data.Type;
using Core.Model.Ingredients.Presentable.Visibles;
using Core.Model.Util;

using System.Collections;
using Engine;

namespace Core.Model.Ingredients.Presentable.TokenManagers
{
    public class ListGroup : TokenGroup
    {
        //private static String GetClass()
       // {
       //     return typeof(ListGroup)//  "Core.Model.ListGroup";
       // }

        #region  Exchanged attributes
        private List<Point> positions = new List<Point>();

        public List<Point> Positions
        {
            get { return positions; }
            set { positions = value; }
        }
        private bool wrapAround = false;

        public bool WrapAround
        {
            get { return wrapAround; }
            set { wrapAround = value; }
        }
        private bool multipleSelection = false;

        public bool MultipleSelection
        {
            get { return multipleSelection; }
            set { multipleSelection = value; }
        }
        #endregion

        #region  Internal attributes

        //private List<ItemListItem> itemList = new List<ItemListItem>();
        private ArrayList itemList = new ArrayList();
        public ArrayList ItemList
        {
            get { return itemList; }
            set { itemList = value; }
        }
        private int firstItem = 1;

        public int FirstItem
        {
            get { return firstItem; }
            set { firstItem = value; }
        }

        #endregion

        //#region  Events

        //private List<Link> firstItemPresented = new List<Link>();

        //public List<Link> FirstItemPresented
        //{
        //    get { return firstItemPresented; }
        //    set { firstItemPresented = value; }
        //}

        //private List<Link> lastItemPresented = new List<Link>();

        //public List<Link> LastItemPresented
        //{
        //    get { return lastItemPresented; }
        //    set { lastItemPresented = value; }
        //}
        //private List<Link> headItems = new List<Link>();

        //public List<Link> HeadItems
        //{
        //    get { return headItems; }
        //    set { headItems = value; }
        //}
        //private List<Link> tailItems = new List<Link>();

        //public List<Link> TailItems
        //{
        //    get { return tailItems; }
        //    set { tailItems = value; }
        //}
        //private List<Link> itemSelected = new List<Link>();

        //public List<Link> ItemSelected
        //{
        //    get { return itemSelected; }
        //    set { itemSelected = value; }
        //}
        //private List<Link> itemDeselected = new List<Link>();

        //public List<Link> ItemDeselected
        //{
        //    get { return itemDeselected; }
        //    set { itemDeselected = value; }
        //}

        //#endregion

        //#region  Event processing
        //public override void handle ( Events.Event evnt )
        //{
        //    switch ( evnt.Type )
        //    {
        //        case enumEvents.FirstItemPresented:
        //            foreach ( Link l in FirstItemPresented )
        //                l.fire( ( ( FirstItemPresented ) evnt ).Data );
        //            break;

        //        case enumEvents.LastItemPresented:
        //            foreach ( Link l in LastItemPresented )
        //                l.fire( ( ( LastItemPresented ) evnt ).Data );
        //            break;

        //        case enumEvents.HeadItems:
        //            foreach ( Link l in HeadItems )
        //                l.fire( ( ( HeadItems ) evnt ).Data );
        //            break;

        //        case enumEvents.TailItems:
        //            foreach ( Link l in TailItems )
        //                l.fire( ( ( TailItems ) evnt ).Data );
        //            break;

        //        case enumEvents.ItemSelected:
        //            foreach ( Link l in ItemSelected )
        //                l.fire( ( ( ItemSelected ) evnt ).Data );
        //            break;

        //        case enumEvents.ItemDeselected:
        //            foreach ( Link l in ItemDeselected )
        //                l.fire( ( ( ItemDeselected ) evnt ).Data );
        //            break;

        //        default:
        //            base.handle( evnt );
        //            break;
        //    }
        //}

        //public override void addLink ( Link link )
        //{
        //    if ( link.LinkCondition.EventSource.Equals( ObjectIdentifier ) )
        //    {
        //        switch ( link.LinkCondition.EventType )
        //        {
        //            case enumEvents.FirstItemPresented:
        //                firstItemPresented.Add( link );
        //                break;

        //            case enumEvents.LastItemPresented:
        //                lastItemPresented.Add( link );
        //                break;

        //            case enumEvents.HeadItems:
        //                headItems.Add( link );
        //                break;

        //            case enumEvents.TailItems:
        //                tailItems.Add( link );
        //                break;

        //            case enumEvents.ItemSelected:
        //                itemSelected.Add( link );
        //                break;

        //            case enumEvents.ItemDeselected:
        //                itemDeselected.Add( link );
        //                break;

        //            default:
        //                base.addLink( link );
        //                break;
        //        }
        //    }
        //    base.addLink( link );
        //}
        //#endregion


        #region  Internal behaviours
        public override void Activate ()
        {
            base.Activate();
            update();
        }

        public override void Deactivate ()
        {
            foreach ( ItemListItem ili in ItemList )
                ( ( Visible ) Engine.MHEGEngine.Instance.Find( ili.ObjectRef ) ).Deactivate();

            base.Deactivate();
        }

        public override void Prepare ()
        {
            base.Prepare();

            foreach ( TokenGroupItem tgi in TokenGroupItems )
                if ( !itemList.Contains( tgi.ObjectRef ) )
                    itemList.Add( new ItemListItem( tgi.ObjectRef, false ) );
        }

        public override void Destroy ()
        {
            foreach ( ItemListItem ili in ItemList )
                ( ( Visible ) Engine.MHEGEngine.Instance.Find( ili.ObjectRef ) ).ResetPosition();

            base.Destroy();
        }

        public void update ()
        {
            //HashSet<ObjectRef> presented = new HashSet<ObjectRef>();
            //List<ObjectRef> presented = new List<ObjectRef>();
            ArrayList presented = new ArrayList();
            int itemIndex = firstItem;

            //  Iterate the cells updating and activating the current visibles appropriately
            foreach ( Point pos in Positions )
            {
                //  If we're meant to wrap around and have hit the upper bound of the item list, go back to cell #1
                if ( itemIndex == itemList.Count && wrapAround )
                    itemIndex = 1;

                //  If we've got a valid item index, get the visible, and set its position correctly.
                if ( itemIndex < itemList.Count )
                {
                    Visible visible = ( Visible ) Engine.MHEGEngine.Instance.Find( ( ( ItemListItem ) itemList [itemIndex] ).ObjectRef );

                    if ( !presented.Contains( visible ) )
                    {
                        presented.Add( visible.ObjectIdentifier );
                        visible.SetPosition( pos.X, pos.Y );
                        if ( RunningStatus && !visible.RunningStatus )
                            visible.Activate();
                    }
                }

                itemIndex++;
            }

            //  Now iterate those visibles which are not current, and deactivate them
            foreach ( ItemListItem ili in ItemList )
            {
                if ( !presented.Contains( ili ) )
                {
                    Visible visible = ( Visible ) Engine.MHEGEngine.Instance.Find( ili.ObjectRef );
                    visible.ResetPosition();

                    if ( RunningStatus && visible.RunningStatus )
                        visible.Deactivate();
                }
            }
        }

        public void addItem ( int index, ObjectRef item )
        {
            if ( !itemList.Contains( item ) && index >= 0 && index <= itemList.Count )
            {
                itemList.Insert( index, new ItemListItem( item ) );
                update();
            }
        }

        public void delItem ( ObjectRef item )
        {
            if ( itemList.Contains( item ) )
            {
                itemList.Remove( item );
                ( ( Visible ) Engine.MHEGEngine.Instance.Find( item ) ).ResetPosition();
                update();
            }
        }

        public void select ( int itemIndex )
        {
            for ( int index = 0 ; index < itemList.Count ; index++ )
            {
                //  todo: check the second bit of the conditional works as intended :)
                ItemListItem ili = ( ItemListItem ) itemList [index];
                if ( !multipleSelection && !( ili.SelectionStatus = false ) )
                    deselect( index );
            }

            if ( itemIndex < itemList.Count )
            {
                ItemListItem select = ( ItemListItem ) itemList [itemIndex];
                select.SelectionStatus = true;
                Engine.MHEGEngine.Instance.Handle( new ItemSelected( this, itemIndex ) );
            }
        }

        public void deselect ( int itemIndex )
        {
            if ( itemIndex < itemList.Count )
            {
                ItemListItem deselect = ( ItemListItem ) itemList [itemIndex];

                if ( deselect.SelectionStatus )
                {
                    deselect.SelectionStatus = false;
                    Engine.MHEGEngine.Instance.Handle( new ItemDeselected( this, itemIndex ) );
                }
            }
        }
        #endregion

        #region  Actions
        public void AddItem ( GenericInteger itemIndex, GenericObjectRef visible )
        {
            //  Normalise to 0 based form
            addItem( itemIndex.Value - 1, visible.Value );
        }

        public void DelItem ( GenericObjectRef visible )
        {
            delItem( visible.Value );
        }

        public void GetListItem ( GenericInteger itemIndex, ObjectRefVariable itemRefVar )
        {
            //  Normalise to 0 based form
            int index = itemIndex.Value - 1;

            if ( wrapAround && ( index < 0 || index >= itemList.Count ) )
                index = index % itemList.Count;

            if ( index >= 0 && index < itemList.Count )
                itemRefVar.Value =  ( ( ItemListItem ) itemList [index] ).ObjectRef;
        }

        public void GetCellItem ( GenericInteger cellIndex, ObjectRefVariable itemRefVar )
        {
            //  todo: implement this icky function
            itemRefVar.Value =  null;
        }

        public void GetItemStatus ( GenericInteger itemIndex, BooleanVariable itemStatusVar )
        {
            itemStatusVar.Value = ( ( ItemListItem ) itemList [itemIndex.Value - 1] ).SelectionStatus;
        }

        public void SelectItem ( GenericInteger itemIndex )
        {
            //  Normalise to 0 based form
            int index = itemIndex.Value - 1;

            if ( wrapAround && ( index < 0 || index >= itemList.Count ) )
                index %= itemList.Count;

            if ( index >= 0 && index < itemList.Count )
                select( index );
        }

        public void DeselectItem ( GenericInteger itemIndex )
        {
            //  Normalise to 0 based form
            int index = itemIndex.Value;

            if ( wrapAround && ( index < 0 || index >= itemList.Count ) )
                index %= itemList.Count;

            if ( index >= 0 && index < itemList.Count )
                deselect( index );
        }

        public void ToggleItem ( GenericInteger itemIndex )
        {
            //  Normalise to 0 based form
            int index = itemIndex.Value;

            if ( wrapAround && ( index < 0 || index >= itemList.Count ) )
                index %= itemList.Count;

            //  todo: finish off this class
        }
        #endregion
    }
}